/*================================================================
 *   Copyright (C) 2021 All rights reserved.
 *   
 *   文件名称：scheduler.h
 *   创 建 者：汉森伯逸
 *   创建日期：2021/3/21
 *   描    述：
 *
 *================================================================*/
#pragma once

#include <memory>
#include <vector>
#include <list>
#include <unordered_map>
#include "thread.h"
#include "fiber.h"
#include "log.h"
#include "util/nolock_queue.h"
#include "util/concurrentqueue.h"

namespace  hsby {

/**
 * @brief 任务上下文可以是协程也可以是回调
 */
struct Task {
    typedef std::shared_ptr<Task> Ptr;

    template<typename ...ArgsType>
    static Task::Ptr Create(ArgsType ...args) {
        return Task::Ptr(new Task(args...));
    }

    /**
     * @brief 为了std容器执行默认初始化, 定义默认构造函数
     */
    Task() : thread_id(-1) {
    }

    Task(Fiber::Ptr f, int thrid = -1)
            : thread_id(f->GetThreadId()), fiber(f){
    }

    Task(std::function<void ()> f, int thrid = -1)
            : thread_id(thrid),  cb(f) {
    }

    Task(std::function<void ()>* f, int thrid = -1)
            :  thread_id(thrid) {
        cb.swap(*f);
    }

    ~Task() {
        Reset();
    }

    void Reset() {
        thread_id = -1;
        fiber.reset();
        cb = nullptr;
    }

    int                     thread_id   = -1;
    Fiber::Ptr              fiber       = nullptr;
    std::function<void()>   cb          = nullptr;
};

/**
 * @brief 线程协程调度器
 */
class Scheduler : public BaseDump{
public:
    typedef RWMutex MutexType;

public:
    /**
     * @brief 构造函数
     */
    Scheduler(size_t worker_count = 1, const std::string& name = "");

    /**
     * @brief 虚析构函数
     */
    virtual ~Scheduler();

public:
    void Dump(std::ostream &os) const override;

public:
    /**
     * @brief 初始化
     */
    virtual bool Init();

    /**
     * @brief 开始
     */
    virtual bool Start();

    /**
     * @brief 停止
     */
    virtual bool Stop();

private:
    /**
     * @brief 工作流程
     */
    virtual void OnWorking();

protected:
    /**
     * @brief 工作流程
     */
    virtual void OnIdle();

    virtual void Tickle(int thread_id = -1);

    virtual bool IsStopped();

public:
    /**
     * @brief 添加任务
     * @param[in] task 任务
     */
    void AddTask(Task::Ptr task);

    /**
     * @brief 添加任务
     * @param[in] cb 回调
     * @param[in] thread_id 指定线程id
     */
    template<typename FiberOrCb>
    void AddTask(FiberOrCb foc, int thread_id = -1) {
        AddTask(Task::Create(foc, thread_id));
    }

    /**
     * @brief 添加任务
     * @param[in] begin 迭代器
     * @param[in] end 迭代器
     */
    template<typename IterFiberOrCb>
    void AddTask(IterFiberOrCb begin, IterFiberOrCb end, int thread_id = -1) {
        for (; begin != end; begin++) {
            AddTask(*begin, thread_id);
        }
    }

    /**
     * @brief 获取名称
     */
    const std::string GetName() const {
        return name_;
    }

    uint64_t GetIdleWorkerCount(){
        return idle_worker_count_;
    }

    uint64_t GetActiveWorkerCount(){
        return active_worker_count_;
    }

public:
    /**
     * @brief 获取当前协程调度器
     */
    static Scheduler* GetCurrentScheduler();

    /**
     * @brief 设置当前协程调度器
     */
    static void SetCurrentScheduler(Scheduler* schedulerPtr);

    /**
     * @brief 获取当前主协程
     */
    static Fiber::Ptr GetThreadWorkingFiber();

protected:
    MutexType                                   mutex_;                             // 互斥锁
    std::string                                 name_;                              // 调度器名称
    size_t                                      worker_count_= 0;                   // 线程数量
    moodycamel::ConcurrentQueue<Task::Ptr>      tasks_ ;
//    NoLockQueue<Task::Ptr>                      ;
    std::atomic<bool>                           is_stop = {false};
    std::atomic<size_t>                         active_worker_count_ = {0};         // 活跃线程数量
    std::atomic<size_t>                         idle_worker_count_ = {0};           // 闲置线程数量
    std::unordered_map<int, Thread::Ptr>        workers_;
    std::vector<int> worker_thread_ids;
};

} // namespace hsby